home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Adobe Graphics & Publishing SDK 1996 December
/
Adobe Graphics & Publishing SDK 1996 December.iso
/
mac
/
After Effects 3.1 SDK Mac
/
Examples
/
Effects Samples
/
Gamma (No Table)
/
GammaNoTable.c
< prev
Wrap
Text File
|
1996-11-06
|
10KB
|
338 lines
/**
GammaNoTable.c
Part of the Adobe After Effects 3.1 SDK.
Copyright (c)1993-96, Adobe Systems Inc, All Rights Reserved.
This effect does a simple gamma correction of the image pixels.
It converts each pixel to a double, applies the gamma power,
and then converts back to 0-255. Needless to say, this is
quite slow. See the GammaWithTable.c file for a different
version of the effect that is a bit faster...
This demonstrates:
iterating over the image pixels (w/o using the Iterate callback)
calling the progress callback
requiring an FPU to operate
a Fixed Slider control
using the Extent Hint rectangle (from the InData structure)
this actually has some interesting complications,
see the Render routine below for explanation...
Revision History
1.0, created by rb, 12 March 93
1.1, updated for AE 2.0, dmw, 11 Jan 94
1.2, updated for Mac/Power Mac dmw, 13 Oct 94
also fixed bug in iterating over input extent (whoops!)
2.0, updated for AE 3.0
2.1, Added call to AEFX_CLR_STRUCT macro to clear out PF_ParamDef, ba, 6 Nov 96
**/
#include "AE_EffectCB.h"
#include "AE_Macros.h"
#include <A4Stuff.h>
#define MAJOR_VERSION 2
#define MINOR_VERSION 0
#define BUG_VERSION 0
#define STAGE_VERSION PF_Stage_RELEASE
#define BUILD_VERSION 0
#define NAME "Gamma (No Table)"
/** Parameter Definition Constants
Here we define the parameters, their default
settings, and minimum and maximum values.
**/
enum {
GAMMA_INPUT = 0, /* params index of default input layer */
GAMMA_GAMMA, /* params index of gamma correction factor */
GAMMA_NUM_PARAMS
};
/* We'll allow the gamma correction factor slider vary
* from 0.1 to 5.0, with the default being at 1.0...
* If the user brings up the direct number entry dialog,
* we'll let them type in a value up to 10.0, even though
* the slider values will stop at 5.0...
* All of these numbers are in Fixed point.
*/
#define GAMMA_MIN 6554 /* approx 0.1 in fixed point */
#define GAMMA_MAX (5L << 16)
#define GAMMA_BIG_MAX (10L << 16)
#define GAMMA_DFLT (1L << 16)
/** Command Specific Subroutines
This plug-in only deals with the commands:
PF_Cmd_ABOUT
PF_Cmd_GLOBAL_SETUP
PF_Cmd_GLOBAL_SETDOWN
PF_Cmd_PARAMS_SETUP
PF_Cmd_RENDER
All other commands are ignored. There is a routine for
each command, and a main routine to dispatch at the bottom.
**/
#define DESCRIPTION "Perform simple (slow) image gamma correction."
static PF_Err About (
PF_InData *in_data,
PF_OutData *out_data,
PF_ParamDef *params[],
PF_LayerDef *output )
{
PF_SPRINTF(out_data->return_msg, "%s, v%d.%d\r%s",
NAME, MAJOR_VERSION, MINOR_VERSION, DESCRIPTION);
return PF_Err_NONE;
}
static PF_Err GlobalSetup (
PF_InData *in_data,
PF_OutData *out_data,
PF_ParamDef *params[],
PF_LayerDef *output )
{
PF_Err err = PF_Err_NONE;
/* Need to let AE know what version of the "Basic Gamma" plug-in
* we are......
*/
out_data->my_version = PF_VERSION(MAJOR_VERSION, MINOR_VERSION,
BUG_VERSION, STAGE_VERSION, BUILD_VERSION);
/* We are only going to iterate over the visible pixels,
* i.e. the extent_hint rect, so we need to specify the
* output extent flags. No flag is necessary to use the input extent
*
*
* Each result pixel in the output buffer depends only on the value of
* the corresponding input pixel, so I'll also set the PIX_INDEPENDENT OutFlag,
* which can speed up the rendering of field-rendered animations tremendously.
* Be careful when setting this flag, though; if you set it when it's not true,
* field rendered output can be quite wrong.
*/
out_data->out_flags |=
PF_OutFlag_PIX_INDEPENDENT |
PF_OutFlag_USE_OUTPUT_EXTENT;
return err;
}
static PF_Err GlobalSetdown (
PF_InData *in_data,
PF_OutData *out_data,
PF_ParamDef *params[],
PF_LayerDef *output )
{
/* We haven't actually allocated any global data,
* so we don't need to do anything here...
*/
return PF_Err_NONE;
}
static PF_Err ParamsSetup (
PF_InData *in_data,
PF_OutData *out_data,
PF_ParamDef *params[],
PF_LayerDef *output )
{
PF_Err err = PF_Err_NONE;
PF_ParamDef def; /* scratch space for a parameter definition */
/* Always clear out the PF_ParamDef structure before adding your parameters,
* this macro will do that.
*/
AEFX_CLR_STRUCT(def);
/* Create the FIXED SLIDER parameter... */
def.param_type = PF_Param_FIX_SLIDER;
PF_STRCPY(def.name, "Gamma");
/* NOTE: we must set these strings to empty strings to prevent
* garbage text from being displayed above our sliders... */
def.u.fd.value_str[0] = def.u.fd.value_desc[0] = '\0';
def.u.fd.value = def.u.fd.dephault = GAMMA_DFLT;
/* The min value of the slider and the min value the user
* can type in will both be the same value... */
def.u.fd.valid_min = def.u.fd.slider_min = GAMMA_MIN;
/* The max value of the slider will be smaller than the
* max value the user can type in. This way, the slider
* has a nice feel to it, but the user who really wants
* strange results can access larger values... */
def.u.fd.slider_max = GAMMA_MAX;
def.u.fd.valid_max = GAMMA_BIG_MAX;
/* Let's let the user see 1 decimal place of precision. */
def.u.fd.precision = 1;
def.u.fd.display_flags = 0;
if (err = PF_ADD_PARAM(in_data, -1, &def)) return err;
/* Set number of parameters before leaving */
out_data->num_params = GAMMA_NUM_PARAMS;
return err;
}
/* Render
* To render our image, we will iterate over all the pixels,
* leaving the alpha untouched, and converting the RGB values
* into floating point, then applying the gamma correction
* to the values and converting them back again. We require
* an FPU. You will note that 68881 code generation has been
* turned on in the THINK C code generation options. */
static PF_Err Render (
PF_InData *in_data,
PF_OutData *out_data,
PF_ParamDef *params[],
PF_LayerDef *output )
{
PF_Err err = PF_Err_NONE;
long x, y, w, h, row_gutter_s, row_gutter_d;
PF_Pixel *in, *out;
double temp, gamma;
/* If the gamma factor is exactly 1.0 just make a direct copy and return now... */
if (params[GAMMA_GAMMA]->u.fd.value == (1L << 16)) {
err = PF_COPY(¶ms[0]->u.ld, output, NULL, NULL);
} else {
/* We are only going to gamma correct the pixels in the
* in_data extent_hint rectangle. But there may be pixels
* in the output extent that are not covered by the in_data
* extent. In that case, we need to clear those pixels to
* zero alpha. Here, we check if there are pixels in the
* output outside of the range we will set, and clear them
* if we have to. (Just for fun, you can try commenting
* out this part and seeing what happens... Try masking the
* image.)
*/
if (in_data->extent_hint.left != output->extent_hint.left ||
in_data->extent_hint.top != output->extent_hint.top ||
in_data->extent_hint.right != output->extent_hint.right ||
in_data->extent_hint.bottom != output->extent_hint.bottom) {
err = PF_FILL(NULL, &output->extent_hint, output);
}
if (!err) {
gamma = (double)params[GAMMA_GAMMA]->u.fd.value / (double)(1L << 16);
gamma = 1.0 / gamma; /* exponent value is reciprocal of gamma */
x = in_data->extent_hint.left;
y = in_data->extent_hint.top;
w = in_data->extent_hint.right - x;
h = in_data->extent_hint.bottom - y;
in = (PF_Pixel *)((char *)(params[GAMMA_INPUT]->u.ld.data + x) +
(y * params[GAMMA_INPUT]->u.ld.rowbytes));
out = (PF_Pixel *)((char *)(output->data + x) + (y * output->rowbytes));
/* NOTE: do not make the assumption here that the input and output
* buffers have the same rowbytes. In After Effects 1.0, that
* was true, but it is not safe in general.
*/
row_gutter_d = output->rowbytes - ((long)w * sizeof(PF_Pixel));
row_gutter_s = params[GAMMA_INPUT]->u.ld.rowbytes - ((long)w * sizeof(PF_Pixel));
for (; y < h; y++) {
for (x = 0; x < w; x++) {
out->alpha = in->alpha;
temp = (double)in->red / 255.0;
temp = PF_POW(temp, gamma);
out->red = (unsigned char)(temp * 255.0);
temp = (double)in->green / 255.0;
temp = PF_POW(temp, gamma);
out->green = (unsigned char)(temp * 255.0);
temp = (double)in->blue / 255.0;
temp = PF_POW(temp, gamma);
out->blue = (unsigned char)(temp * 255.0);
/* move to the next pixel */
in++;
out++;
}
/* move to the start of the next row */
in = (PF_Pixel *)((char *)in + row_gutter_s);
out = (PF_Pixel *)((char *)out + row_gutter_d);
/* update the progress bar -- we're about to start line y+1 */
if (err = PF_PROGRESS(in_data, y + 1, h)) break;
}
}
}
return err;
}
PF_Err main (
PF_Cmd cmd,
PF_InData *in_data,
PF_OutData *out_data,
PF_ParamDef *params[],
PF_LayerDef *output )
{
PF_Err err = PF_Err_NONE;
EnterCodeResource(); /* only works in Metrowerks */
switch (cmd) {
case PF_Cmd_ABOUT:
err = About(in_data,out_data,params,output);
break;
case PF_Cmd_GLOBAL_SETUP:
err = GlobalSetup(in_data,out_data,params,output);
break;
case PF_Cmd_PARAMS_SETUP:
err = ParamsSetup(in_data,out_data,params,output);
break;
case PF_Cmd_GLOBAL_SETDOWN:
err = GlobalSetdown(in_data,out_data,params,output);
break;
case PF_Cmd_RENDER:
err = Render(in_data,out_data,params,output);
break;
}
ExitCodeResource(); /* only works in Metrowerks */
return err;
}